#ifndef DLNA_PLAY_CONTROLLER_H
#define DLNA_PLAY_CONTROLLER_H

#include <chrono>
#include <mutex>
#include <thread>
#include <memory>
#include <unordered_map>
#include "i_stream_player_impl.h"
#include "i_stream_player_listener_impl.h"
#include "i_cast_stream_manager_client.h"
#include "cast_stream_common.h"
#include "cast_local_file_channel_server.h"
#include "cast_timer.h"
#include "dlna_manager.h"
#include "dmcApi.h"
#include "dmcApiTypes.h"
#include "utils.h"
#include "handler.h"
#include "message.h"
#include "json.hpp"
using nlohmann::json;

namespace OHOS {
namespace CastEngine {
namespace CastEngineService {

class DlnaPlayController : public IStreamPlayerImpl, public std::enable_shared_from_this<DlnaPlayController>,
    public Handler, public Message {
public:
    static uint32_t DlnaGetLocalFd(char *uri);
    static unsigned long DlnaDmpDeviceDownInd(unsigned long deviceId, void* auxData);
    DlnaPlayController(std::shared_ptr<ICastStreamManagerClient> callback,
        std::shared_ptr<CastLocalFileChannelServer> fileChannel, uint32_t deviceId);
    ~DlnaPlayController() override;

    void SetSessionCallbackForRelease(const std::function<void(void)>& callback);
    int32_t RegisterListener(sptr<IStreamPlayerListenerImpl> listener) override;
    int32_t UnregisterListener() override;
    int32_t SetSurface(sptr<IBufferProducer> producer) override;
    int32_t Load(const MediaInfo &mediaInfo) override;
    int32_t Play(const MediaInfo &mediaInfo) override;
    int32_t Play(int index) override;
    int32_t Play() override;
    int32_t Pause() override;
    int32_t Stop() override;
    int32_t Next() override;
    int32_t Previous() override;
    int32_t Seek(int position) override;
    int32_t FastForward(int delta) override;
    int32_t FastRewind(int delta) override;
    int32_t SetVolume(int volume) override;
    int32_t SetMute(bool mute) override;
    int32_t SetLoopMode(const LoopMode mode) override;
    int32_t SetAvailableCapability(const StreamCapability &streamCapability) override;
    int32_t SetSpeed(PlaybackSpeed speed) override;
    int32_t GetPlayerStatus(PlayerStates &playerStates) override;
    int32_t DlnaGetPlayerStatus(PlayerStates &dlnaPlayerStates);
    int32_t GetPosition(int &position) override;
    int32_t GetDuration(int &duration) override;
    int32_t GetVolume(int &volume, int &maxVolume) override;
    int32_t DlnaGetVolume(int &dlnaVolume, int &maxVolume);
    int32_t GetMute(bool &mute) override;
    int32_t GetLoopMode(LoopMode &loopMode) override;
    int32_t GetPlaySpeed(PlaybackSpeed &playbackSpeed) override;
    int32_t GetMediaInfoHolder(MediaInfoHolder &mediaInfoHolder) override;
    int32_t ProvideKeyResponse(const std::string &mediaId, const std::vector<uint8_t> &response) override;
    int32_t GetAvailableCapability(StreamCapability &streamCapability) override;
    int32_t Release() override;

private:
    class DlnaCallbackImpl : public DlnaCallback {
    public:
        explicit DlnaCallbackImpl(std::weak_ptr<DlnaPlayController> controller) : controller_(controller) {}
        virtual ~DlnaCallbackImpl() {}
        void OnDeviceOffline(unsigned long deviceId) override;
 
    private:
        std::weak_ptr<DlnaPlayController> controller_;
    };
    enum DlnaUpnpMediaType {
        INVALID = -1,
        AUDIO,
        VIDEO,
        IMAGE,
        FOLDER,
    };
    enum DlnaStatus : int {
        STOPPED,
        PLAYING,
    };
    enum DlnaActionId {
        INIT,
        PUSH,
        PLAY,
        PAUSE,
        STOP,
        NEXT,
        PREVIOUS,
        SEEK,
        SET_VOLUME,
        SET_MUTE,
        SET_LOOP_MODE,
    };
    enum MessageId : int {
        DLNA_MSG_PLAY  = 5,
        DLNA_MSG_PAUSE = 6,
        DLNA_MSG_STOP  = 9,
    };
    std::string DlnaGetUpnpClass(DlnaUpnpMediaType mediaInfoType);
    std::string DlnaGetMetaData(DlnaUpnpMediaType mediaInfoType, std::string url, const MediaInfo &mediaInfo);
    std::pair<int, std::string> PlayOnlineMedia(const MediaInfo &mediaInfo);
    std::pair<int, std::string> PlayLocalMedia(const MediaInfo &mediaInfo);
    int32_t TimeStringToInt(const std::string& timeString);
    int32_t GetTimeInfo(int* position, int* duration);
    bool GetMediaTypeEnumFromString(std::string mediaTypeString, DlnaUpnpMediaType& type);
    std::string SpeedToString(PlaybackSpeed speed);
    bool AutoUpdateCurInfo();
    bool AutoUpdateCurPosition();
    bool AutoUpdatePlayerState();
    bool AutoUpdateVolume();
    bool DisconnectSession(std::string deviceId);
    void NotifyPlayerError(int errorCode, const std::string &errorMsg);
    static std::string DlnaSeek(int position);
    std::string ReplaceAll(std::string resource_str, std::string sub_str, std::string new_str);
    std::string ReplaceUrl(std::string resource_str);
    void OnDeviceOffline(unsigned long deviceId);
    int32_t PlayInner(const MediaInfo &mediaInfo);
    int32_t PauseInner();
    int32_t StopInner();
    void HandleMessage(const Message &msg) override;
    std::string MediaInfoToJson(const MediaInfo &mediaInfo);
    MediaInfo JsonToMediaInfo(const nlohmann::json& jsonMediaInfo, MediaInfo& mediaInfo);

protected:
    sptr<IStreamPlayerListenerImpl> PlayerListenerGetter();
    std::mutex sessionCallbackMutex_;
    std::mutex listenerMutex_;
    std::function<void(void)> sessionCallback_;
    std::weak_ptr<ICastStreamManagerClient> callback_;
    std::shared_ptr<CastLocalFileChannelServer> fileChannelServer_;
    DlnaDmc::DmcApi dmcApi_;
    PlaybackSpeed currentSpeed_ = PlaybackSpeed::SPEED_FORWARD_1_00_X;
    uint32_t dlnaDevId_{0};
    constexpr static uint32_t MAX_PRIVATE_URI_LEN = 1024;

private:
    constexpr static int32_t DLNA_POSITION_UPDATE_INTERVAL = 300;
    constexpr static int32_t DLNA_MIL_SECOND = 1000;
    constexpr static int32_t DLNA_TIME_DIVIDER = 60;
    constexpr static int32_t DECIMAL_10 = 10;
    constexpr static int32_t DLNA_STOP_COUNT = 2;
    static std::weak_ptr<ICastStreamManagerClient> dlnaCallback_;
    static std::unordered_map<std::string, DlnaUpnpMediaType> mediaTypeMap;
    static std::unordered_map<DlnaUpnpMediaType, std::string> mediaSuffixMap;
    static std::unordered_map<PlaybackSpeed, std::string> speedMap;
    static std::string testErrorCodeParam_;
    std::shared_ptr<CastTimer> timer_ = std::make_shared<CastTimer>();
    int currentPosition_{0};
    int durationPosition_{ 0 };
    std::atomic<PlayerStates> playerStates_{PlayerStates::PLAYER_IDLE};
    std::atomic<int> stoppedCnt_{0};
    bool firstGetPosition_{ true };
    bool firstGetState_{ true };
    bool firstBuffering_{true};
    int needSeekPosition_{ -1 };
    int volume_{0};
    std::shared_ptr<DlnaCallbackImpl> dlnaCallbackImpl_;
    nlohmann::json jsonMediaInfo;
    int subVectorSize = 2;

public:
    bool firstStart = true;
    static sptr<IStreamPlayerListenerImpl> playerListener_;
    static std::condition_variable fdCondition_;
    static std::mutex fdMutex_;
    static int fd_;
    static MediaInfo mediaInfo_;
    static bool autoUpdate_;
    std::string pucTrackURI_;
    int pucRelTime_ = 0;
};
} // namespace CastEngineService
} // namespace CastEngine
} // namespace OHOS
#endif // DLNA_PLAY_CONTROLLER_H